package com.wiscamp.ninechapters.problems.domain.models.problems.problems;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.wiscamp.ninechapters.ddd.AggregateRoot;
import com.wiscamp.ninechapters.problems.domain.models.problems.questions.Question;
import com.wiscamp.ninechapters.problems.domain.models.types.ProblemType;
import com.wiscamp.ninechapters.problems.enums.Actions;
import com.wiscamp.ninechapters.problems.enums.DifficultyLevels;
import com.wiscamp.ninechapters.tags.domain.models.TagName;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;

/**
 * 题
 */
@Data
public class Problem implements AggregateRoot {
    /**
     * 题编号
     */
    private long problemId;

    private long problemTypeId = 0;

    private double problemScore = 0;

    private int timeLimit = 0;

    private int difficulty = 0;

    private String remark = "";

    private boolean enabled = true;

    private boolean deleted = false;

    private long creatorId = 0;

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime creationTime;

    private long modifierId = 0;

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    private LocalDateTime modificationTime;

    private String collectionName = "";

    private String problemTypeName = "";

    private String creatorName = "";

    private String modifierName = "";

    private long stemId = 0;

    private long collectionId = 0;

    private long partId = 0;

    private long sectionId = 0;

    private int problemIndex = 0;

    private ProblemType problemType;

    private String questionModeName = "";

    /*public String getQuestionModeName() {
        if (Objects.isNull(problemType) || Objects.isNull(problemType.getCommonQuestionMode()))
            return "Unknown";
        return problemType.getCommonQuestionModeName();
    }*/

    /**
     * 关联主要知识点列表
     */
    private Collection<ProblemKnowledgePoint> primaryKnowledgePoints = new ArrayList<>();

    /**
     * 关联次要知识点列表
     */
    private Collection<ProblemKnowledgePoint> minorKnowledgePoints = new ArrayList<>();

    /**
     * 关联标签列表
     */
    private Collection<TagName> tagNames = new ArrayList<>();

    /**
     * 是否有题干
     */
    protected boolean hasStem = false;

    protected boolean hasMultipleQuestions = false;

    public void setCurrentQuestion(@NotNull Question question) {
    }

    public Question getCurrentQuestion() {
        return null;
    }


    public void setCurrentQuestions(@NotEmpty Collection<Question> questions) {
    }

    public Collection<Question> getCurrentQuestions() {
        return new ArrayList<>();
    }

    public void addQuestion(@NotNull Question question) {
    }

    // region entity methods
    public double getTotalScore() {
        var questions = new ArrayList<Question>();
        if (this.getCurrentQuestions().isEmpty()) {
            questions.add(this.getCurrentQuestion());
        } else {
            questions.addAll(this.getCurrentQuestions());
        }

        double score = 0;
        for (var question : questions) {
            score = score + question.getQuestionScore();
        }
        return score;
    }

    public int getAverageDifficulty() {
        var questions = new ArrayList<Question>();
        if (this.getCurrentQuestions().isEmpty()) {
            questions.add(this.getCurrentQuestion());
        } else {
            questions.addAll(this.getCurrentQuestions());
        }

        int totalDifficulty = 0;
        for (var question : questions) {
            totalDifficulty = totalDifficulty + question.getDifficulty();
        }
        return totalDifficulty / questions.size();
    }

    public int getCurrentDifficulty() {

        if (difficulty > 0)
            return difficulty;
        else
            return getAverageDifficulty();
    }

    public double getCurrentScore() {
        if (problemScore > 0)
            return problemScore;
        else
            return getTotalScore();
    }

    public DifficultyLevels getDifficultyLevel() {
        var difficulty = getCurrentDifficulty();
        if (difficulty > 100)
            return DifficultyLevels.EXTREMELY_HARD;
        else if (difficulty > 80)
            return DifficultyLevels.VERY_HARD;
        else if (difficulty > 60)
            return DifficultyLevels.HARD;
        else if (difficulty > 40)
            return DifficultyLevels.NORMAL;
        else if (difficulty > 20)
            return DifficultyLevels.EASY;
        else if (difficulty > 0)
            return DifficultyLevels.VERY_EASY;

        return DifficultyLevels.NORMAL;
    }

    // endregion

    //private String questionModeName = "";


    public void setCurrentStem(@NotNull Stem stem) {
        //
    }

    public Stem getCurrentStem() {
        return null;
    }

    public Collection<ProblemKnowledgePoint> getKnowledgePoints() {
        var list = new ArrayList<ProblemKnowledgePoint>();
        list.addAll(primaryKnowledgePoints);
        list.addAll(minorKnowledgePoints);
        return list;
    }


    public void enable() {
        if (!this.enabled) {
            this.enabled = true;
        }
    }

    public void disable() {
        if (this.enabled) {
            this.enabled = false;
        }
    }

    public void delete() {
        if (!this.deleted) {
            this.deleted = true;
        }
    }

    public void createBy(long operatorId) {
        this.creatorId = operatorId;
        this.creationTime = LocalDateTime.now();
        this.modifierId = operatorId;
        this.modificationTime = LocalDateTime.now();
    }

    public void updateBy(long operatorId) {
        this.modifierId = operatorId;
        this.modificationTime = LocalDateTime.now();
    }

    public boolean validate() {
        return true;
    }

    private Actions action = Actions.NONE;
}
